/*
#include "gndconnect.h"
#include "gndapp.h"
#include "gndglobal.h"
//#include <stdio.h>
*/

#include "gnd.h"

struct _GndConnect
{
    GObject parent;
    gchar * device_id;
    GMainContext * network_context;
    GMainLoop * network_mainloop;
    GMainContext * main_context;
    GThread * network_thread;
    GMutex * mutex_connecting;

    GndApp * app;
};

G_DEFINE_TYPE(GndConnect, gnd_connect, G_TYPE_OBJECT)


void gnd_connect_thread_start(GndConnect * self);
gboolean gnd_connect_adb_init(GndConnect * self);

void gnd_connect_class_init(GndConnectClass *klass)
{}

void gnd_connect_init(GndConnect *self)
{
    self->network_context = NULL;
    self->network_mainloop = NULL;
    self->main_context = g_main_context_default();
    self->network_thread = NULL;
    /*
    self->network_thread = g_thread_new("GND_CONNECT_THREAD",
                                        (GThreadFunc) gnd_connect_thread_start,
                                        (gpointer) self);
    */
    self->mutex_connecting = g_new(GMutex, 1);
    g_mutex_init(self->mutex_connecting);

}


GndConnect * gnd_connect_new(GndApp *app)
{
    GndConnect * self = g_object_new(GND_TYPE_CONNECT, NULL);
    self->app = GND_APP(app);
    //self->device_id = g_strdup(device_id);
    return self;
}


gboolean gnd_connect_set_deviceid(GndConnect * self, gchar *d_id)
{
    if (!g_mutex_trylock(self->mutex_connecting)) {
        return FALSE;
    } else {
        self->device_id = g_strdup(d_id);
        g_mutex_unlock(self->mutex_connecting);
        return TRUE;
    }
}

gchar * gnd_connect_get_deviceid(GndConnect *self)
{
    return self->device_id;
}

gboolean gnd_connect_start(GndConnect *self)
{
    //获取连接锁
    if (!g_mutex_trylock(self->mutex_connecting)) {
        return FALSE;
    }

    if (!gnd_connect_adb_init(self)) {
        return FALSE;
    }

    self->network_thread = g_thread_new("GND_CONNECT_THREAD",
                                        (GThreadFunc) gnd_connect_thread_start,
                                        (gpointer) self);
    return TRUE;
}

gboolean gnd_connect_stop(GndConnect *self)
{
    if (g_mutex_trylock(self->mutex_connecting)) {
        g_mutex_unlock(self->mutex_connecting);
        return FALSE;
    }

    g_main_loop_quit(self->network_mainloop);
    g_thread_join(self->network_thread);
    g_main_loop_unref(self->network_mainloop);
    g_main_context_unref(self->network_context);
    g_thread_unref(self->network_thread);

    self->network_mainloop = NULL;
    self->network_context = NULL;
    self->network_thread = NULL;

    g_mutex_unlock(self->mutex_connecting);

    return TRUE;
    //g_thread
}

//run in other thread
void gnd_connect_thread_start(GndConnect *self)
{
    self->network_context = g_main_context_new();
    //self->network_mainloop = g_main_loop_new(self->network_context, FALSE);
    g_main_context_push_thread_default(self->network_context);
    self->network_mainloop = g_main_loop_new(self->network_context, FALSE);
    g_main_loop_run(self->network_mainloop);
}

//检查网络县城是否在运行，并不一位这设备之间连接已建立
gboolean gnd_connect_is_connecting(GndConnect *self)
{
    if (g_mutex_trylock(self->mutex_connecting)) {
        g_mutex_unlock(self->mutex_connecting);
        return FALSE;
    } else {
        return TRUE;
    }
}


gboolean gnd_connect_adb_init(GndConnect *self)
{

    //return TRUE;

    gchar param[16] = "tcp:";
    gchar port_str[8] = {'\0'};

    g_snprintf(port_str, 8, "%d", PORT);
    g_strlcat(param, port_str, 16);

    gchar * argv[] = {
        gnd_app_get_setting_str(self->app, "adb_path"),
        "-s", self->device_id,
        "forward",
        param,
        param,
        NULL
    };

    gchar * std_error = NULL;

    if (!g_spawn_sync(NULL, argv, NULL,
                      G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL,
                      NULL, NULL, NULL, &std_error, NULL, NULL)) {
        return FALSE;
    }

    if (!std_error && std_error[0] != 0) {
        return FALSE;
    }

    return TRUE;
}


gboolean gnd_connect_add_session(GndConnect *self, GndSession *session)
{
    if (!gnd_connect_is_connecting(self) || !session) {
        return FALSE;
    }

    GError * error = NULL;
    session->connect = self;
    session->socket = g_socket_new(G_SOCKET_FAMILY_IPV4,
                                   G_SOCKET_TYPE_STREAM,
                                   G_SOCKET_PROTOCOL_TCP,
                                   &error);
    g_assert(!error);
    g_socket_set_blocking(session->socket, FALSE);
    GSocketAddress * address = g_inet_socket_address_new_from_string("127.0.0.1", PORT);
    //g_socket_connect(session->socket, G_SOCKET_ADDRESS(address), NULL, NULL);
    /*
    if(!g_socket_connect(session->socket, G_SOCKET_ADDRESS(address), NULL, NULL))
    {
        g_object_unref(address);
        g_object_unref(session->socket);
        session->socket = NULL;
        return FALSE;
    }
    */

//    g_object_unref(address);
    g_socket_set_timeout(session->socket, 5);
    GSource * socket_source = g_socket_create_source(session->socket,
                                                     G_IO_OUT, NULL);
    g_source_set_callback(socket_source,
                          (GSourceFunc) gnd_session_connect_finished_cb,
                          (gpointer) session, NULL);
    g_socket_connect(session->socket, G_SOCKET_ADDRESS(address), NULL, NULL);
    g_source_attach(socket_source, self->network_context);
    return TRUE;
}


GMainContext * gnd_connect_get_main_context(GndConnect *self)
{
    g_assert(self);
    return self->main_context;
}


gboolean gnd_connect_attach_source(GndConnect *connect, GSource *source)
{
    if (!gnd_connect_is_connecting(connect)) {
        return FALSE;
    }

    g_source_attach(source, connect->network_context);
    return TRUE;
}
